package service

import (
	"crypto/md5"
	"fmt"
	"github.com/astaxie/beego/logs"
	"time"
)

var (
	secKillConf *SecKillConf
)

func SecInfoById(productId int) (data map[string]interface{}, code int, err error) {
	secKillConf.RwSecProductLock.RLock()
	v, ok := secKillConf.SecProductInfoMap[productId]
	if !ok {
		code = ErrNotFoundProductId
		err = fmt.Errorf("not found productId:%d ", productId)
		return
	}
	start := false
	end := false
	status := "success"

	now := time.Now().Unix()
	if now < v.StartTime {
		start = false
		end = false
		status = "sec kill is not start"
		code = ErrActiveNotStart
	} else {
		start = true
		status = "sec kill is begin"
	}
	if now < v.EndTime {
		end = false
	} else {
		end = true
		status = "sec kill is over"
		code = ErrActiveAlreadyEnd
	}

	if v.Status == ProductStatusForceSaleOut || v.Status == ProductStatusSaleOut {
		start = false
		end = true
		status = "product is sale out"
		code = ErrAciveSaleOut
	}

	data = make(map[string]interface{})
	data["productId"] = productId
	data["start"] = start
	data["end"] = end
	data["status"] = status

	secKillConf.RwSecProductLock.RUnlock()
	return

}

func SecInfoList() (data []map[string]interface{}, code int, err error) {
	secKillConf.RwSecProductLock.RLock()
	for k, _ := range secKillConf.SecProductInfoMap {
		item, _, err := SecInfoById(k)
		if err != nil {
			logs.Error("productId:[%v] get error", k)
			continue
		}
		data = append(data, item)
	}
	secKillConf.RwSecProductLock.RUnlock()
	return
}

func UserCheck(req *SecRequest) (err error) {
	found := false
	for _, refer := range secKillConf.ReferWhiteList {
		if refer == req.ClientReferer {
			found = true
			break
		}
	}
	if !found {
		err = fmt.Errorf("invalid request")
		logs.Warn("user[%d] is reject by refer,req[%v]", req.UserId, req)
		return
	}

	authData := fmt.Sprintf("%d:%s", req.UserId, secKillConf.CookieSecretKey)
	authSign := fmt.Sprintf("%x", md5.Sum([]byte(authData)))
	if authSign != req.UserAuthSign {
		err = fmt.Errorf("invalid user cookie auth")
		return
	}
	return
}

func SecKill(req *SecRequest) (data map[string]interface{}, code int, err error) {
	secKillConf.RwSecProductLock.RLock()
	defer secKillConf.RwSecProductLock.RUnlock()
	err = UserCheck(req)
	if err != nil {
		code = ErrUserCheckAuthFailed
		logs.Warn("userId[%d] invalid,check failed,req[%v]", req.UserId, req)
		return
	}
	err = AntiSpam(req)
	if err != nil {
		code = ErrUserServiceBusy
		logs.Warn("userId[%d] invalid,check failed,req[%v]", req.UserId, req)
	}
	data, code, err = SecInfoById(req.ProductId)
	if err != nil {
		logs.Warn("userId[%d] invalid,check failed,req[%v]", req.UserId, req)
		return
	}
	if code != 0 {
		logs.Warn("userId[%d] secInfoById failed code[%d] req[%v]", req.UserId, code, req)
		return
	}

	secKillConf.SecReqChan <- req

	return
}
